/**
 * 
 */
package com.jsecode.lib.lang;

import java.lang.ref.SoftReference;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * LRUMap: 实现最近最少使用原则的Map <br/>
 * 1.在调用get()，put()方法的时候，影响到的元素会被放置在Iterator的首部<br/>
 * 2.遍历时不能进行put、get操作，否则会抛出ConcurrentModificationException异常<br/>
 * 3.已修改为线程安全的<br/>
 */
@SuppressWarnings("serial")
public class LRUMap<K, V> {
	
	class LRUMapImpl<IK, IV> extends LinkedHashMap<IK, IV> {
		
		// 因为LRUMap在读的时候也有写操作,所以不使用ReadWriteLock
		private final ReentrantLock lock = new ReentrantLock();
		
		private final int maxSize;
		
		/**
		 * 构造函数
		 * 
		 * @param initCapacity
		 *            int 此map的初始化大小
		 * @param maxSize
		 *            int 此map最大容量，如map插入的数值超过此大小，最早被访问的元素将会被抛弃
		 */
		public LRUMapImpl(int initCapacity, int maxSize) {
			super(initCapacity, 0.75f, true);
			this.maxSize = maxSize;
		}
		
		/**
		 * @param maxSize
		 *            此map的最大容量，初始大小为最大容量的1/4
		 */
		public LRUMapImpl(int maxSize) {
			super(maxSize >> 2, 0.75f, true);
			this.maxSize = maxSize;
		}
		
		/**
		 * 删除
		 */
		protected boolean removeEldestEntry(Map.Entry<IK, IV> eldest) {
			return this.size() >= maxSize;
		}
		
		/*
		 * (non-Javadoc)
		 * @see java.util.LinkedHashMap#get(java.lang.Object)
		 */
		@Override
		public IV get(Object key) {
			try {
				lock.lock();
				return super.get(key);
			} finally {
				lock.unlock();
			}
		}
		
		/*
		 * (non-Javadoc)
		 * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
		 */
		@Override
		public IV put(IK key, IV val) {
			try {
				lock.lock();
				return super.put(key, val);
			} finally {
				lock.unlock();
			}
		}
	}
	
	private LRUMapImpl<K, SoftReference<V>> _CACHE;
	
	/**
	 * 构造函数
	 * 
	 * @param initCapacity
	 *            int 此map的初始化大小
	 * @param maxSize
	 *            int 此map最大容量，如map插入的数值超过此大小，最早被访问的元素将会被抛弃
	 */
	public LRUMap(int initCapacity, int maxSize) {
		_CACHE = new LRUMapImpl<K, SoftReference<V>>(initCapacity, maxSize);
	}
	
	/**
	 * @param maxSize
	 *            此map的最大容量，初始大小为最大容量的1/4
	 */
	public LRUMap(int maxSize) {
		_CACHE = new LRUMapImpl<K, SoftReference<V>>(maxSize);
	}
	
	/**
	 * 写入key和value
	 * 
	 * @param key
	 * @param val
	 * @return
	 */
	public V put(K key, V val) {
		SoftReference<V> r = new SoftReference<V>(val);
		SoftReference<V> v = _CACHE.put(key, r);
		return v == null ? null : v.get();
	}
	
	/**
	 * 根据key获取value
	 * 
	 * @param key
	 * @return
	 */
	public V get(K key) {
		SoftReference<V> r = _CACHE.get(key);
		return r == null ? null : r.get();
	}
	
	/**
	 * 删除缓存中数据
	 * 
	 * @param key
	 * @return
	 */
	public V remove(K key) {
		SoftReference<V> r = _CACHE.remove(key);
		return r == null ? null : r.get();
	}
	
	/**
	 * 清除全部数据
	 */
	public void clear() {
		_CACHE.clear();
	}

	/**    
	 * @return    
	 */
	public Set<K> keySet() {
		return _CACHE.keySet();
	}
}
